/**
 *
 */
#include "CfgParser.h"
#include "applog.h"
#include "plog.h"
#include <libgen.h>
#include <assert.h>

CfgParser::CfgParser(){/*{{{*/
	cfg = NULL;
	//pthread_rwlock_init( &cfg_lock , NULL );
	memset( &cfg_stat , 0 , sizeof(struct stat) );
}

CfgParser::~CfgParser(){
	//pthread_rwlock_destroy( &cfg_lock );
	if( cfg ){
#ifdef OWN_PROFILE
		cfg->Clear();
#else
		cfg_free(cfg);
		cfg = NULL;
#endif
	}
}/*}}}*/
#ifdef OWN_PROFILE
bool CfgParser::Initialize(const string& file_path ){/*{{{*/ 
#else
bool CfgParser::Initialize( cfg_opt_t * opts , const string& file_path ){
#endif

	
	SetCfgPath(file_path);
	if( GetCfgStat() < 0 ){
		LEPLOG( LEVEL_CRITICAL , "GetCfgStat failed in Initialize()" );
		return false;
	}
#ifdef OWN_PROFILE
	cfg = CProfile::Instance();
#else
	cfg = cfg_init(opts, CFGF_NONE);
#endif
	if( NULL == cfg ){
		EPLOG( "cfg_init failed" );
		return false;
	}

	if( !CfgParse() ){
		EPLOG( "CfgParse failed" );
		return false;
	}
	return true;
}
/*}}}*/

/**
 * return: more than 0 - CfgFile is changed
 *         equal to  0 - CfgFile isn't changed
 *         less than 0 - Something Failed 
 */
int CfgParser::GetCfgStat(){/*{{{*/

	struct stat buf;
	if( stat(cfg_fpath.c_str() , &buf ) ){
		LEPLOG( LEVEL_CRITICAL , "Can not find the configuration file");
		return -1;
	}

//	if( memcmp(&buf, &cfg_stat, sizeof(struct stat) ) ){
	if( buf.st_mtime!= cfg_stat.st_mtime ){
		memcpy( &cfg_stat , &buf , sizeof( struct stat ));
		return 1;
	}
	
	return 0;
}/*}}}*/

bool CfgParser::CfgParse(){/*{{{*/

#ifdef OWN_PROFILE
	if( !cfg->ParseFile( cfg_fpath ) ){
		LEPLOG( LEVEL_CRITICAL ,"cfg->ParseFile failed in CfgParse()" );
		return false;
	}
#else
	switch(cfg_parse(cfg, cfg_fpath.c_str())){
	case CFG_SUCCESS:
		break;
	case CFG_FILE_ERROR:
		LEPLOG( LEVEL_CRITICAL, "cfg_parse(CFG_FILE_ERROR) failed in CfgParse()");
		return false;
	case CFG_PARSE_ERROR:
		LEPLOG( LEVEL_CRITICAL, "cfg_parse(CFG_PARSE_ERROR) failed in CfgParse()");
		return false;
	}
#endif
	return true;
}/*}}}*/
/**
 *
 */
void CfgParser::SetCfgPath( const string& file_path ){/*{{{*/

 	cfg_fpath = file_path;	
	return ;
}/*}}}*/

bool CfgParser::Update(){/*{{{*/

	assert( cfg );

	int retval = GetCfgStat();

	if( retval == 0 ){
		return false;
	}else if ( retval < 0 ){
		LEPLOG( LEVEL_CRITICAL,"GetCfgStat failed in Update()");
		return false;
	}

	PLOG( "Config should be updated now");
	//pthread_rwlock_wrlock( &cfg_lock );
	if( !CfgParse() ){
		LEPLOG( LEVEL_CRITICAL ,"CfgParse failed in Update()");
	}
	//pthread_rwlock_unlock( &cfg_lock );
	
	return true;
}/*}}}*/

bool CfgParser::GetSessName( const string& item , string& secname ){/*{{{*/
	string item_tmp = item;

	char *s = (char *)malloc(item_tmp.size()+1);
	if( NULL == s ){
		throw( "malloc failed!\n" );
	}
	memset(s, 0, item_tmp.size()+1 );
	strncpy( s, item_tmp.c_str() , item_tmp.size() );
	char * ret_val =dirname( s );
	secname = ret_val;
	free( s );
	return true ; 
}/*}}}*/

bool CfgParser::GetKey( const string& item , string& key ){/*{{{*/
	string item_tmp = item;
	char *s = (char *)malloc(item_tmp.size()+1);
	if( NULL == s ){
		throw( "malloc failed!\n" );
	}
	memset(s, 0, item_tmp.size()+1 );
	strncpy( s, item_tmp.c_str() , item_tmp.size() );
	char * ret_val =basename( s );
	key = ret_val;
	free( s );
	return true; 
}/*}}}*/

string CfgParser::GetStr( const string& item ){/*{{{*/
	string ret_val;
	//pthread_rwlock_rdlock( &cfg_lock );
#ifdef OWN_PROFILE
	string secname;
	string key;
	GetSessName( item , secname );
	GetKey( item , key );
	if( !cfg->GetSectionKV( secname , key , ret_val)){
		throw( "GetSectionKV failed!" );
	}
#else
	ret_val = cfg_getstr( cfg ,item.c_str() );
#endif
	//pthread_rwlock_unlock( &cfg_lock );

	return ret_val; 
}/*}}}*/

bool CfgParser::GetBool( const string& item ){/*{{{*/
	bool ret_val = false;
	//pthread_rwlock_rdlock( &cfg_lock );
#ifdef OWN_PROFILE
	string ret_str = GetStr( item );	
	if( (0 == strcasecmp(ret_str.c_str() , "yes")	) ||
	    (0 == strcasecmp(ret_str.c_str() , "true")	) ){
		ret_val = true;
	}else{
		ret_val = false;
	}
#else
	ret_val = cfg_getbool( cfg , item.c_str() );
#endif
	//pthread_rwlock_unlock( &cfg_lock );

	return ret_val;
}/*}}}*/

int CfgParser::GetInt( const string& item ){/*{{{*/
	int ret_val;
	//pthread_rwlock_rdlock( &cfg_lock );
#ifdef OWN_PROFILE
	string ret_str = GetStr( item );	
	
	ret_val = atoi( ret_str.c_str() );
#else
	ret_val = cfg_getint( cfg , item.c_str() );
#endif
	//pthread_rwlock_unlock( &cfg_lock );

	return ret_val; 
}/*}}}*/

vector<string> CfgParser::GetList( const string& item ){/*{{{*/
	vector <string> retvec;
	//pthread_rwlock_rdlock( &cfg_lock );
#ifdef OWN_PROFILE
	string ret_str = GetStr( item );	
        char *d=",";
        char *p;
	char *s = (char *)malloc(ret_str.size()+1);
	if( NULL == s ){
		throw( "malloc failed!\n" );
	}
	memset(s, 0, ret_str.size()+1 );
	strncpy( s, ret_str.c_str() , ret_str.size() );
	p=strtok( s, d);
	while(p){
		retvec.push_back( p );
		p=strtok(NULL,d);
	}

	free(s);
#else
	int i;
        for(i = 0; i < cfg_size(cfg, item.c_str()) ; i++){
		retvec.push_back( cfg_getnstr(cfg , item.c_str(),i) );

	}
#endif
	//pthread_rwlock_unlock( &cfg_lock );
	return retvec;
}/*}}}*/
